package com.kylin.common.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.kylin.common.core.entity.DataEntity;
import com.kylin.common.core.entity.TreeEntity;
import com.kylin.common.core.exception.CheckException;
import com.kylin.common.core.mapper.TreeMapper;
import com.kylin.common.core.service.TreeService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 通用树形结构服务接口实现
 *
 * @author wuhao
 * @version 1.0 - 2019/6/25
 */
//@Transactional(rollbackFor = Exception.class)
public abstract class TreeServiceImpl<M extends TreeMapper<T>, T extends TreeEntity<T>> extends BaseServiceImpl<M, T> implements TreeService<T> {

    /** 父节点列表字段 */
    private static final String PARENT_IDS_FIELD = "parent_ids";
    /** 状态字段 */
    private static final String STATUS_FIELD = "status";

    /**
     * 根据ID查询对象
     * @param id 主键ID
     * @return
     * @version 1.0  by wuhao at 2019-03-12
     */
    @Override
    public T getById(Serializable id){
        T item = this.mapper.selectById(id);
        // 设置缓存
        if(item != null) {
            this.setCache(Arrays.asList(item));
        }
        return item;
    }

    /**
     * 获取单个对象
     *
     * @param entity 实体对象T
     * @return
     * @version 1.0  by wuhao at 2019-03-12
     */
    @Override
    public T get(T entity) {
        QueryWrapper<T> queryWrapper = getQueryWrapper(entity);
        T item =  this.mapper.selectOne(queryWrapper);

        // 设置缓存
        if(item != null) {
            this.setCache(Arrays.asList(item));
        }

        return item;
    }

    /**
     * 根据条件获取list结果
     *s
     * @param entity 实体对象
     * @return
     * @version 1.0  by wuhao at 2019-03-12
     */
    @Override
    public List<T> list(T entity) {
        QueryWrapper<T> queryWrapper = getQueryWrapper(entity);
        // 加上sql过滤
        queryWrapper.apply(StringUtils.isNotBlank(entity.getSqlFilter()),entity.getSqlFilter());

        List<T> list = this.mapper.selectList(queryWrapper);

        // 设置缓存数据
        this.setCache(list);

        return list;
    }

    /**
     * 新增数据
     * @param entity 实体对象
     * @return
     * @version 1.0  by wuhao at 2019-03-12
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insert(T entity) {
        // 保存信息
        int count = this.mapper.insert(this.generateTreeEntity(entity));
        // 清除缓存信息
        this.clearCache();
        return count;
    }


    /**
     * 更新数据
     *
     * @param entity 实体对象
     * @return
     * @version 1.0  by wuhao at 2019-03-12
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(T entity) {
        // 主要逻辑：
        // 1. 校验数据合法性
        // 2. 更新自己的数据
        // 3. 更新自己子节点的数据

        // 数据校验
        QueryWrapper<T> where = new QueryWrapper<>();
        where.select("id").like(PARENT_IDS_FIELD, entity.getId() + ",");
        List<Object> childIds = this.mapper.selectObjs(where);
        if(childIds.contains(entity.getParentId()) || entity.getId().equals(entity.getParentId())) {
            throw new CheckException("父节点不能为自己或自己的子节点");
        }

        // 更新信息
        int count = this.mapper.updateById(this.generateTreeEntity(entity));

        // 更新所有子节点信息（父节点列表，名称全路径，，排序列表,层级）  通过截取的方式替换,前面截掉换现有
        T oldEntity = getById(entity.getId());
        this.mapper.updateChild(oldEntity, entity);

        // 清除缓存信息
        this.clearCache();

        return count;
    }

    /**
     * 保存数据（插入或更新）
     * 实现自动保存字段：所有父级编号、所有排序号、是否是叶子节点、节点的层次级别等数据
     * 实现级联更新所有子节点数据：同父级自动保存字段
     * @param entity 树节点
     * @return
     * @version 1.0  by wuhao at 2019-08-13
     */
    @Override
    public int save(T entity) {
        if(ObjectUtils.isEmpty(entity.getId())){
            entity.perInsert();
            return insert(entity);
        }else{
            entity.perUpdate();
            return update(entity);
        }
    }

    /**
     * 删除数据（级联删除子节点）
     *
     * @param id 主键ID
     * @return
     * @version 1.0  by wuhao at 2019-08-13
     */
    @Override
    public int delete(Serializable id) {
        QueryWrapper<T> where = new QueryWrapper<>();
        /**删除自己 ，删除自己的子节点   parent_codes like '0,xxx,yyy'; */
        TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
        where.eq(true, tableInfo.getKeyColumn(), id).or(true).like(true, PARENT_IDS_FIELD, "," + id + ",");
        int count = this.mapper.delete(where);
        // 清空缓存
        this.clearCache();
        return count;
    }

    
    /**
     * 根据编号获取所有子节点列表
     * @param
     * @return 
     * @version 1.0  by wuhao at 2020-12-07
     */
    public List<T> listChildren(Serializable id) {
        QueryWrapper<T> where = new QueryWrapper<>();
        where.like(PARENT_IDS_FIELD, id + ",");
        return this.mapper.selectList(where);
    }

    /**
     * 将简单列表code，parentCode转换为嵌套列表格式【code,children[code,children[...]]】
     *
     * @param sourceList 源数据列表
     * @param parentId 目标数据列表的顶级节点
     * @return
     * @version 1.0  by wuhao at 2019-08-13
     */
    @Override
    public List<T> convertChildList(List<T> sourceList, Serializable parentId) {
         return sourceList.stream().filter(entity -> Objects.equals(entity.getParentId(), parentId))
                .map(entity -> {
                    entity.setChildren(getChildNode(entity, sourceList));
                    return entity;
                }).collect(Collectors.toList());
    }

    private List<T> getChildNode(T root, List<T> treeList) {
        return treeList.stream().filter(entity -> Objects.equals(entity.getParentId(), root.getId()))
                .map(entity -> {
                    entity.setChildren(getChildNode(entity, treeList));
                    return entity;
                })
                .sorted(Comparator.comparingInt(o -> (o.getTreeSort() == null ? 0 : o.getTreeSort())))
                .collect(Collectors.toList());
    }

    /**
     * 查询状态正常的子节点列表
     * @param id 节点id
     * @return 状态正常子节点类别
     * @since  2.1.0  by wuhao at 2021-05-06
     */
    public List<T> selectNormalChildrenById(Long id) {
        QueryWrapper<T> where = new QueryWrapper<>();
        where.eq(STATUS_FIELD, DataEntity.STATUS_NORMAL);
        where.like(PARENT_IDS_FIELD, id + ",");
        return this.mapper.selectList(where);
    }

    /**
     * 设置缓存，此方法一般用于系统不怎么变化的数据
     * 目前作用于： list, get, getById
     * @version 1.0  by wuhao at 2020-12-28
     */
    protected void setCache(List<T> list) {

    }

    /**
     * 清除缓存，此方法一般用于系统不怎么变化的数据
     * 目前作用于： save， insert， update， delete
     * @version 1.0  by wuhao at 2020-12-28
     */
    protected void clearCache() {

    }

    /**
     * 统一组装一个tree对象(新)
     */
    private T generateTreeEntity(T entity) {

        String parentIds = "";
        String treeLabels = "";
        String treeSorts = "";

        // 如果父节点为空，表示为主节点
        if(entity.getParentId() == null || TreeEntity.ROOT_CODE.equals(entity.getParentId())) {
            entity.setParentId(0L);
        } else {
            T parent = getById(entity.getParentId());
            // 判断父节点是否停用，停用不允许新增 add by wuhao at 20210506
            if (!DataEntity.STATUS_NORMAL.equals(parent.getStatus()))
            {
                throw new CheckException("上级节点已停用，不允许操作");
            }
            parentIds = parent.getParentIds();
            treeLabels = parent.getTreeLabels();
            treeSorts = parent.getTreeSorts();
        }

        // 设置所有父节点列表 格式：0,xxxx,
        entity.setParentIds(parentIds + entity.getParentId() + ",");
        // 设置树的名称列表 格式：蜂云科技/研发部
        entity.setTreeLabels(treeLabels + "/" + entity.getLabel());

        // 默认排序 30
        entity.setTreeSort(entity.getTreeSort() == null?  TreeEntity.DEFAULT_TREE_SORT: entity.getTreeSort());
        // 所有树排序，方便排序 格式： 00030,00040
        entity.setTreeSorts(treeSorts + StringUtils.leftPad(entity.getTreeSort() + "", 5, "0") + ",");

        return entity;
    }

    /** 构建通用查询条件 */
    private QueryWrapper<T> getQueryWrapper(T entity) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        // 无查询条件时，将对象放入查询对象中，方便快速查询
        if(entity.getQueryWrapper().isEmptyOfWhere()){
            queryWrapper.setEntity(entity);
        } else {
            queryWrapper = entity.getQueryWrapper();
        }
        return queryWrapper;
    }
}
